package com.example.mytips.structure;

import com.example.mytips.utils.FFList;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBPanel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.jcef.JBCefApp;

import com.intellij.util.ui.UIUtil;
import org.apache.http.util.TextUtils;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;


/// 实现这个类ToolWindowFactory，就是边边的窗口

/**
 * 列出 当前.dart文件 的方法列表
 */
public class FlutterPlusWindow implements ToolWindowFactory {

    private Project project;
    private ToolWindow toolWindow;

    List<String> lineList;
    List<MarkEntity> markList;
    List<ClassEntity> classList;

    private int methodNameWidth = 200;

    private int returnValueWidth = 100;

    private JBList<StructureDialogEntity> structureList;

    private String markSymbol = "mark-";

    @Override
    public void createToolWindowContent(Project project, ToolWindow toolWindow) {
        CustomSaveAction.flutterPlusWindow = this;
        this.project = project;
        this.toolWindow = toolWindow;
//        if (!JBCefApp.isSupported()) {
//            System.out.println("不支持");
//            return;
//        }

        initUI();

        // 注册 FileEditorManagerListener
        project.getMessageBus().connect().subscribe(
                FileEditorManagerListener.FILE_EDITOR_MANAGER,
                new FileEditorManagerListener() {

                    /**
                     * 文件切换
                     */
                    @Override
                    public void selectionChanged(@NotNull FileEditorManagerEvent event) {

                        VirtualFile file = event.getNewFile();
                        if (file == null) {
                            System.out.println("提示：file = null");
                            return;
                        }

                        // 获取 PsiFile
                        PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
                        if (psiFile == null) {
//                            ApplicationManager.getApplication().invokeLater(() -> {
//                                Messages.showInfoMessage(project, "无法解析 PSI 文件", "提示");
//                            });
                            return;
                        }

                        // 在这儿获取当前 Editor对象,Editor对象不对的话，操作的内容就不对了
                        Editor editor = getCurrentEditor(project);
                        handlePsiFile(editor, psiFile);
                    }
                }
        );

    }


    public void outRefreshUI() {

        if (this.structureList == null) {
            initUI();
        }

        // 获取当前活动的编辑器和文件
        if (this.structureList == null) {
//            ApplicationManager.getApplication().invokeLater(() -> {
//                Messages.showInfoMessage(project, "this.structureList = null", "提示");
//            });
            return;
        }

        Editor editor = getCurrentEditor(project);
        if (editor == null) {
//            ApplicationManager.getApplication().invokeLater(() -> {
//                Messages.showInfoMessage(project, "当前没有活动的编辑器", "提示");
//            });
            return;
        }

        PsiFile psiFile = getCurrentPsiFile(project, editor);
        if (psiFile != null) {
            handlePsiFile(editor, psiFile);
        } else {
//            ApplicationManager.getApplication().invokeLater(() -> {
//                Messages.showInfoMessage(project, "psiFile = null", "提示");
//            });
        }
    }


    /**
     * 布局UI
     */
    private void initUI() {
        JBList<StructureDialogEntity> structureList = new JBList<>();
        this.structureList = structureList;
        structureList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        ///点击事件
        structureList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 1) {
                    // 获取子目录名称
                    StructureDialogEntity entity = structureList.getSelectedValue();
                    System.out.println("行数 " + entity.line + " ,选中了 " + entity.name);


                    // 点击的就亮起来
                    for (int i = 0; i < structureList.getItemsCount(); i++) {
                        StructureDialogEntity item = structureList.getModel().getElementAt(i);
                        item.initSelected = false;
                    }
                    entity.initSelected = true;

                    ///将光标定位到指定行
                    Editor editor = getCurrentEditor(project);
                    if (editor != null) {
                        editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(entity.line, 0));
                        editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
                    }
                }
            }
        });

        ///布局
        structureList.setCellRenderer(new ListCellRenderer<StructureDialogEntity>() {
            @Override
            public Component getListCellRendererComponent(JList<? extends StructureDialogEntity> list, StructureDialogEntity value, int index,
                                                          boolean isSelected, boolean cellHasFocus) {

                // 创建水平布局
                JPanel panel = new JPanel();
                panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));

                if (value.isClass) {
                    ///这是类
                    JLabel name = new JLabel(value.name);
                    name.setPreferredSize(new Dimension(name.getWidth(), 40)); // 设置JLabel的宽度和高度
                    name.setForeground(new Color(255, 255, 255, 200));

                    name.setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD, 14));

                    panel.add(name);

                    ///这是类型
                    String typeStr = value.type;
                    JLabel note = new JLabel("  " + typeStr);
                    note.setForeground(new Color(255, 255, 255, 100));
                    note.setFont(UIUtil.getLabelFont().deriveFont(Font.PLAIN, 12));
                    panel.add(note);
                } else if (value.isMark && !TextUtils.isEmpty(value.name)) {
                    /// 添加注释的组头
                    JLabel groudSymbol = new JLabel("----");
                    panel.add(groudSymbol);

                    JLabel name = new JLabel(value.name);

                    name.setFont(UIUtil.getLabelFont().deriveFont(Font.PLAIN, 12));
                    name.setPreferredSize(new Dimension(name.getWidth(), 30));
                    name.setForeground(new Color(0, 255, 0, 120));

                    panel.setBackground(new Color(28, 28, 28, 80));
                    panel.add(name);
                } else {
                    ///这是方法行

                    JLabel left = new JLabel("  ");
                    panel.add(left);

                    ///方法的icon
                    JLabel mIcon = new JLabel("", IconLoader.getIcon("/icons/m.png", FlutterPlusWindow.class), SwingConstants.CENTER);
                    panel.add(mIcon);

                    ///这是方法名
                    JLabel name = new JLabel("" + value.name);
                    name.setFont(UIUtil.getLabelFont().deriveFont(Font.PLAIN, 12));

                    ///设置宽高
                    Dimension preferredSize = new Dimension(methodNameWidth, 30);
                    name.setPreferredSize(preferredSize);

                    panel.add(name);

                    ///这是返回值
                    JLabel returnValueLabel = new JLabel("  " + value.returnValue);
                    Dimension dimension = new Dimension(returnValueWidth, returnValueLabel.getPreferredSize().height);
                    returnValueLabel.setMaximumSize(dimension);
                    returnValueLabel.setMinimumSize(dimension);
                    returnValueLabel.setPreferredSize(dimension);
                    returnValueLabel.setForeground(Color.gray);
                    returnValueLabel.setFont(UIUtil.getLabelFont().deriveFont(Font.PLAIN, 11));
                    panel.add(returnValueLabel);

                    ///注释
                    if (!TextUtils.isEmpty(value.note)) {
                        String noteStr = value.note;
                        JLabel note = new JLabel(noteStr);
                        note.setForeground(new Color(0, 255, 0, 150));
                        panel.add(note);
                    }


                    ///背景颜色
                    if (index % 2 == 0) {
                        panel.setBackground(new Color(54, 54, 54, 30));
                    } else {
                        panel.setBackground(new Color(28, 28, 28, 30));
                    }

                    ///选中的行的背景颜色
                    if (value.initSelected) {
                        panel.setBackground(new Color(159, 121, 238, 50));
                    }
                }

                return panel;
            }
        });

        /// 新建窗口
        JBPanel panel = new JBPanel(new BorderLayout());
        panel.add(structureList, BorderLayout.CENTER);

        /// 将窗口添加到滚动窗品上
        JBScrollPane scrollPane = new JBScrollPane(panel);

        /// 添加到编辑器窗口上
        ContentFactory contentFactory = ContentFactory.getInstance();
        Content content = contentFactory.createContent(scrollPane, "当前方法列表", false);
        toolWindow.getContentManager().addContent(content);

    }


    /**
     * 更新UI
     */
    private void updateUI(List<ClassEntity> classList, String fileName, Editor editor, int cursorLine) {
        StructureDialogEntity lastMethodEntity = null;
        boolean isExe = false;
        List<StructureDialogEntity> rowList = new ArrayList<>();
        for (int i = 0; i < classList.size(); i++) {
            ClassEntity classEntity = classList.get(i);
            StructureDialogEntity groupEntity = new StructureDialogEntity();
            groupEntity.name = classEntity.name;
            groupEntity.isClass = true;
            groupEntity.line = classEntity.startLineNum;
            groupEntity.type = classEntity.type;
            rowList.add(groupEntity);

            for (int j = 0; j < classEntity.methodList.size(); j++) {
                MethodEntity methodEntity = classEntity.methodList.get(j);

                StructureDialogEntity entity = new StructureDialogEntity();
                entity.name = methodEntity.name;
                entity.note = methodEntity.note;
                entity.isMark = methodEntity.isMark;
                entity.line = methodEntity.startLineNum;
                entity.returnValue = methodEntity.resultValue;
                entity.initSelected = false;

                if (cursorLine - entity.line >= 0 && lastMethodEntity != null) {
                    lastMethodEntity.initSelected = false;
                    entity.initSelected = true;
                } else if (cursorLine - entity.line >= 0 && lastMethodEntity == null) {
                    entity.initSelected = true;
                }

                rowList.add(entity);
                lastMethodEntity = entity;
            }
        }


        // 更新 JBList 的数据模型
        DefaultListModel<StructureDialogEntity> model = new DefaultListModel<>();
        for (StructureDialogEntity entity : rowList) {
            model.addElement(entity);
        }

        if (structureList == null) {
//            ApplicationManager.getApplication().invokeLater(() -> {
//                Messages.showInfoMessage(project, "updateUI structureList == null", "提示");
//            });
            return;
        }
        this.structureList.setModel(model);
        this.structureList.repaint(); // 刷新 UI

    }


    /**
     * 读取文件：psiFile
     */
    public void handlePsiFile(Editor editor, PsiFile psiFile) {
        if (editor == null) {
//            ApplicationManager.getApplication().invokeLater(() -> {
//                Messages.showInfoMessage(project, "editor == null", "提示");
//            });
            return;
        }
        // 文档
        Document document = editor.getDocument();
        // 光标位置
        int offset = editor.getCaretModel().getOffset();

        // 光标的所在的行号
        int cursorLine = document.getLineNumber(offset);

        // 一行一行读取文件
        lineList = new ArrayList<>();
        markList = new ArrayList<>();
        StringBuilder stringBuilder = new StringBuilder();
        try {
            assert psiFile != null;
            try (InputStream inputStream = psiFile.getVirtualFile().getInputStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    // 在这里处理每一行的内容
                    lineList.add(line);
                    if (line.trim().startsWith("///" + markSymbol)) {
                        MarkEntity markEntity = new MarkEntity();
                        markEntity.line = lineList.size() - 1;
                        markEntity.note = line.trim().replace("///" + markSymbol, "");
                        markList.add(markEntity);
                    }
                    stringBuilder.append(line);
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        if (lineList.size() < 1) {
            return;
        }


        classList = new ArrayList<>();
        ClassEntity existClassEntity = null;
        //取出类
        for (int line = 0; line < lineList.size(); line++) {
            String lineStr = lineList.get(line);

            ClassEntity classEntity = null;
            try {
                classEntity = isClass(lineStr, line);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
            if (classEntity != null) {
                ///出现新的类
                existClassEntity = classEntity;
                classList.add(classEntity);
                System.out.println("类名 " + classEntity.name);
            } else {
                ///在现有类中
                MethodEntity methodEntity = null;
                try {
                    methodEntity = isMethod(lineStr, line);
                } catch (Exception e) {
                    System.out.println(e.toString());
                }
                if (methodEntity != null) {
                    ///在现有类中，出现新的方法
                    System.out.println("方法名 " + methodEntity.name);
                    if (existClassEntity != null) {

                        /// 循环取出当前合适的标记内容
                        String markNote = "";
                        int startLineNum = methodEntity.startLineNum;
                        while (!FFList.isEmpty(markList)) {
                            MarkEntity markEntity = markList.get(0);
                            if (markEntity.line - line <= 0) {

                                if (markNote.isEmpty()) {
                                    markNote = markEntity.note;
                                    startLineNum = markEntity.line;
                                } else {
                                    markNote = markNote + " + " + markEntity.note;
                                }
                                markList.remove(0);
                            } else {
                                break;
                            }
                        }

                        //标记的内容：///mark-
                        if (!markNote.isEmpty()) {
                            MethodEntity markEntity = new MethodEntity();
                            markEntity.isMark = true;
                            markEntity.startLineNum = startLineNum;
                            markEntity.name = markNote;
                            existClassEntity.methodList.add(markEntity);
                        }

                        existClassEntity.methodList.add(methodEntity);
                    }
                } else {
                    System.out.println(lineStr);
                }

            }
        }

        updateUI(classList, psiFile.getName(), editor, cursorLine);
    }


    /**
     * 获取当前活动的编辑器
     */
    private Editor getCurrentEditor(Project project) {
        if (project == null) return null;

        if (project.isDisposed()) {
            System.out.println("当前项目已关闭");
            return null;
        }

        return FileEditorManager.getInstance(project).getSelectedTextEditor();
    }

    /**
     * 根据编辑器获取当前文件的 PsiFile
     */
    private PsiFile getCurrentPsiFile(Project project, Editor editor) {
        if (editor == null) return null;
        VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
        if (virtualFile == null) return null;
        return PsiManager.getInstance(project).findFile(virtualFile);
    }


    /**
     * 获取PsiFile
     */
    PsiFile getPsiFile(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
        // 获取当前项目
        Project project = source.getProject();

        // 获取 PsiFile
        PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
        if (psiFile == null) {
            System.out.println("无法解析 PSI 文件: " + file.getName());
            return null;
        }

        return psiFile;
    }

    /**
     * 是否是方法
     */
    MethodEntity isMethod(String lineStr, int line) {
        if (TextUtils.isEmpty(lineStr)) return null;

        ///成员变量和成员方式才会是这个开头
        String blankStr = "  ";

        ///几个过滤条件
        if (!lineStr.startsWith(blankStr)) {
            return null;
        }

        ///去掉最前面的两个空格
        String newLineStr = lineStr.substring(blankStr.length());
        ///如果前面还有两个空格，那一定不是方法
        if (newLineStr.startsWith(blankStr)) {
            return null;
        }

        ///这是注释行
        if (newLineStr.startsWith("*") || newLineStr.startsWith("//")) {
            return null;
        }

        int smallLeftPos = lineStr.indexOf("(");
        int smallRightPos = lineStr.indexOf(")");
        int bigLeftPos = lineStr.indexOf("{");
        int bigRightPos = lineStr.indexOf("}");
        int endPos = lineStr.indexOf(";");

        boolean end = lineStr.endsWith(";");
        boolean bigLeftEnd = lineStr.endsWith("{");
        boolean bigRightEnd = lineStr.endsWith("}");

        /// 找不到(
        if (smallLeftPos == -1) {
            return null;
        }

        ///成员变量的特征，这明显不是方法
        if (lineStr.contains("=>") || lineStr.startsWith("late")) {
            return null;
        }


        if (lineStr.contains("=")) {
            int equalPos = lineStr.indexOf("=");
            if (smallLeftPos < equalPos && equalPos < smallRightPos) {

            } else {
                return null;
            }
        }

        /// 方法特征
        ///  void test() {}
        boolean style1 = smallLeftPos < smallRightPos && bigLeftPos < bigRightPos && bigRightEnd;
        ///  void test() {
        boolean style2 = smallLeftPos < smallRightPos && bigLeftEnd;
        ///  void test();
        boolean style3 = smallLeftPos < smallRightPos && end && lineStr.endsWith(");");
        ///  void test(
        boolean style4 = lineStr.trim().endsWith("(");
        ///  void test({
        boolean style5 = lineStr.trim().endsWith("({");
        ///  test(String kye,
        boolean style6 = lineStr.trim().endsWith(",");
        if (style1 ||
                style2 ||
                style3 ||
                style4 ||
                style5 ||
                style6

        ) {
            MethodEntity methodEntity = new MethodEntity();
            ///所在行
            methodEntity.startLineNum = line;

            ///方法名 和 返回值赋值
            String methodName = lineStr.substring(0, smallLeftPos);

            ///如果>为结尾 形如：Future<IFFR<L>> getFriends<L, E>
            if (methodName.endsWith(">")) {
                int lastIndexOf = methodName.lastIndexOf("<");
                if (lastIndexOf != -1) {
                    methodName = methodName.substring(0, lastIndexOf);
                }
            }

            /// "Widget build",用空格切开，前面的就是返回值，后面的就是方法名
            int lastIndexOf = methodName.lastIndexOf(" ");
            if (lastIndexOf == -1) {
                methodEntity.name = methodName;
            } else {
                methodEntity.name = methodName.substring(lastIndexOf);
                methodEntity.resultValue = methodName.substring(0, lastIndexOf).trim();
            }

            ///方法注释 从当前行往上走，直到遇到"  } xxx"
            ClassEntity classEntity = classList.get(classList.size() - 1);
            int lineStart = -1;
            if (classEntity.methodList.isEmpty()) {
                //第一个方法
                lineStart = classEntity.startLineNum;
            } else {
                //不是第一个方法
                MethodEntity method = classEntity.methodList.get(classEntity.methodList.size() - 1);
                lineStart = method.startLineNum;
            }

            ///获取注释
            List<String> noteList = new ArrayList<>();
            for (int i = line - 1; i > lineStart; i--) {
                String noteStr = lineList.get(i);
                String trim = noteStr.trim();

                if (TextUtils.isEmpty(noteStr) || trim.startsWith("@")) {
                    continue;
                }


                ///去掉最前面的两个空格
                String newNoteStr = noteStr.substring(blankStr.length());
                if (trim.startsWith("/")) {
                    ///这是注释行
                    noteList.add(noteStr);
                    break;
                } else if (trim.startsWith("*")) {
                    noteList.add(noteStr);
                } else {
                    break;
                }

            }

            ///注释格式化
            StringBuilder noteStr = new StringBuilder();
            for (int i = noteList.size() - 1; i >= 0; i--) {
                String noteLine = noteList.get(i);
                noteLine = noteLine.replace("/", "");
                noteLine = noteLine.replace("*", "");
                if (noteLine.length() > 1) {
                    noteStr.append(noteLine);
                }
            }

            String note = noteStr.toString().trim();
            if (!note.startsWith(markSymbol)) {
                methodEntity.note = note;
            }

            return methodEntity;
        }

        return null;
    }

    /**
     * 是否是类
     */
    ClassEntity isClass(String lineStr, int line) {
        if (TextUtils.isEmpty(lineStr)) return null;

        String classStart = "class ";
        String abstractClassStart = "abstract class ";
        String extensionStart = "extension ";
        String enumStart = "enum ";
        String mixinStart = "mixin ";

        boolean isClassStart = lineStr.startsWith(classStart);
        boolean isAbstractClassStart = lineStr.startsWith(abstractClassStart);
        boolean isExtensionStart = lineStr.startsWith(extensionStart);
        boolean isEnumStart = lineStr.startsWith(enumStart);
        boolean isMixinStart = lineStr.startsWith(mixinStart);

        if (isClassStart || isAbstractClassStart || isExtensionStart || isEnumStart || isMixinStart) {

            //取出类名
            String className = "";
            String newLineStr = lineStr;
            if (isClassStart) {
                newLineStr = newLineStr.substring(classStart.length());
            } else if (isAbstractClassStart) {
                newLineStr = newLineStr.substring(abstractClassStart.length());
            } else if (isExtensionStart) {
                newLineStr = newLineStr.substring(extensionStart.length());
            } else if (isEnumStart) {
                newLineStr = newLineStr.substring(enumStart.length());
            } else if (isMixinStart) {
                newLineStr = newLineStr.substring(mixinStart.length());
            }
            String[] splitList = newLineStr.split(" ");
            className = splitList[0];

            ClassEntity classEntity = new ClassEntity();
            classEntity.startLineNum = line;
            classEntity.name = className.trim();
            String[] split = lineStr.split(classEntity.name);

            if (split.length > 0) {
                classEntity.type = split[0].trim();
            }
            return classEntity;
        }

        return null;
    }
}



